package org.moda.sql.visitor;

import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.schema.Column;

import java.util.function.BiFunction;

/**
 * @ClassName: ExpressionVisitor
 * @Description:
 * @Author: xuanyang
 * @Date: 2024-11-23 23:27
 * @Version: 1.0
 **/
public class ExpressionVisitor {
    public static Condition parse(Expression expression) {
        return switch (expression) {
            case AndExpression and -> parseBinaryExpression("AND", (AndExpression) expression);
            case OrExpression or -> parseBinaryExpression("OR", (OrExpression) expression);
//            case BinaryExpression
            case BinaryExpression other -> parseSimpleCondition(other);
            default -> null;
        };
    }

    public static Condition parseBinaryExpression(String operator, BinaryExpression binary) {
        var left = parse(binary.getLeftExpression());
        var right = parse(binary.getRightExpression());
        return new Condition.CompositeCondition(operator, left, right);
    }

    private static Condition parseSimpleCondition(BinaryExpression expression) {
        return extractNameValue(expression.getRightExpression())
            .apply(extractFieldName(expression.getLeftExpression()), expression.getStringExpression());
    }

    private static String extractFieldName(Expression expression) {
        return switch (expression) {
            case Column column -> column.getColumnName();
            default -> null;
        };
    }

    private static BiFunction<String, String, Condition> extractNameValue(Expression expression) {
        return (fieldName, operator) -> switch (expression) {
            case Column column -> new Condition.SampleFieldCondition(fieldName, operator, column.getColumnName());
            case StringValue stringValue -> new Condition.SimpleValueCondition<String>(fieldName, operator, stringValue.getValue());
            case LongValue longValue -> new Condition.SimpleValueCondition<Long>(fieldName, operator, longValue.getValue());
            case DoubleValue doubleValue -> new Condition.SimpleValueCondition<Double>(fieldName, operator, doubleValue.getValue());
            default -> null;
        };
    }
}
